<!DOCTYPE html>
<html lang=zh>
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, minimum-scale=1, user-scalable=no, minimal-ui">
  <meta name="renderer" content="webkit">
  <meta http-equiv="Cache-Control" content="no-transform" />
  <meta http-equiv="Cache-Control" content="no-siteapp" />
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style" content="black">
  <meta name="format-detection" content="telephone=no,email=no,adress=no">
  <!-- Color theme for statusbar -->
  <meta name="theme-color" content="#000000" />
  <!-- 强制页面在当前窗口以独立页面显示,防止别人在框架里调用页面 -->
  <meta http-equiv="window-target" content="_top" />


  <title>商品详情页系统的Servlet3异步化实践[摘抄] | Hexo</title>
  <meta name="description" content="链接：原文  作者：张开涛  在京东工作的这一年多时间里，我在整个商品详情页系统（后端数据源）及商品详情页统一服务系统（页面中异步加载的很多服务，如库存服务、图书相关服务、延保服务等）中使用了Servlet3请求异步化模型，总结了Servlet3请求异步化的一些经验和想法跟大家分享和交流。  我将从如下几点阐述Servlet3异步化之后的好处：1、为什么实现请求异步化需要使用Servlet3 2、">
<meta name="keywords" content="servlet,电商,商品详情页">
<meta property="og:type" content="article">
<meta property="og:title" content="商品详情页系统的Servlet3异步化实践[摘抄]">
<meta property="og:url" content="http://sangshi.oschina.io/2017/09/02/商品详情页系统的Servlet3异步化实践-摘抄/index.html">
<meta property="og:site_name" content="Hexo">
<meta property="og:description" content="链接：原文  作者：张开涛  在京东工作的这一年多时间里，我在整个商品详情页系统（后端数据源）及商品详情页统一服务系统（页面中异步加载的很多服务，如库存服务、图书相关服务、延保服务等）中使用了Servlet3请求异步化模型，总结了Servlet3请求异步化的一些经验和想法跟大家分享和交流。  我将从如下几点阐述Servlet3异步化之后的好处：1、为什么实现请求异步化需要使用Servlet3 2、">
<meta property="og:locale" content="zh-CN">
<meta property="og:image" content="http://ov81buv8l.bkt.clouddn.com/08f25902-862c-3a65-b874-3f51581082ee.png">
<meta property="og:image" content="http://ov81buv8l.bkt.clouddn.com/bbd7dca3-ae05-3723-b5de-59d2d21153fa.png">
<meta property="og:image" content="http://ov81buv8l.bkt.clouddn.com/780114c2-5669-3295-81df-1e298699e59e.png">
<meta property="og:image" content="http://ov81buv8l.bkt.clouddn.com/77d5e01c-9613-3aae-93fa-b96b3f2bc8a7.png">
<meta property="og:image" content="http://ov81buv8l.bkt.clouddn.com/cd442555-c883-3466-bbfd-71c9ac1afb8b.png">
<meta property="og:updated_time" content="2017-09-02T16:28:02.424Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="商品详情页系统的Servlet3异步化实践[摘抄]">
<meta name="twitter:description" content="链接：原文  作者：张开涛  在京东工作的这一年多时间里，我在整个商品详情页系统（后端数据源）及商品详情页统一服务系统（页面中异步加载的很多服务，如库存服务、图书相关服务、延保服务等）中使用了Servlet3请求异步化模型，总结了Servlet3请求异步化的一些经验和想法跟大家分享和交流。  我将从如下几点阐述Servlet3异步化之后的好处：1、为什么实现请求异步化需要使用Servlet3 2、">
<meta name="twitter:image" content="http://ov81buv8l.bkt.clouddn.com/08f25902-862c-3a65-b874-3f51581082ee.png">
  <!-- Canonical links -->
  <link rel="canonical" href="http://sangshi.oschina.io/2017/09/02/商品详情页系统的Servlet3异步化实践-摘抄/index.html">

    <link rel="alternate" href="/atom.xml" title="Hexo" type="application/atom+xml">


    <link rel="icon" href="/favicon.png" type="image/x-icon">

  <!-- font-awesome CSS -->
  <link href="https://cdn.bootcss.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
  <link rel="stylesheet" href="/css/style.css">



</head>


<body class="main-center">
  <section class="mainside">
  <div class="slimContent">
    <div class="navbar-header">


      <div class="profile-block text-center">
        <a id="avatar" href="https://git.oschina.net/sangshi" target="_blank">
          <img class="thumb-xl img-circle img-rotate" src="/images/avatar.jpg" width="200" height="200">
        </a>
        <h2 id="name" class="hidden-xs hidden-sm">sangshi</h2>
        <h3 id="title" class="hidden-xs hidden-sm hidden-md">我欲成仙，法力无边</h3>
        <small id="location" class="text-muted hidden-xs hidden-sm"><i class="fa fa-map-marker"></i> GuangZhou, China</small>
      </div>

      <div class="search" id="search-form-wrap">

    <form class="search-form sidebar-form">
        <div class="input-group">
            <input type="text" class="search-form-input form-control" placeholder="搜索" />
            <span class="input-group-btn">
                <button type="submit" class="search-form-submit btn btn-flat"><i class="fa fa-search"></i></button>
            </span>
        </div>
    </form>
    <div class="ins-search">
    <div class="ins-search-mask"></div>
    <div class="ins-search-container">
        <div class="ins-input-wrapper">
            <input type="text" class="ins-search-input" placeholder="想要查找什么..." x-webkit-speech />
            <button type="button" class="close ins-close ins-selectable" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
            <!-- <span class="ins-close ins-selectable"><i class="fa fa-times"></i></span> -->
        </div>
        <div class="ins-section-wrapper">
            <div class="ins-section-container"></div>
        </div>
    </div>
</div>

</div>
      <button class="navbar-toggle collapsed" type="button" data-toggle="collapse" data-target="#main-navbar" aria-controls="main-navbar" aria-expanded="false">
        <span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
    </div>
    <nav id="main-navbar" class="collapse navbar-collapse">
      <ul class="nav navbar-nav main-nav">



        <li class="menu-item menu-item-home">
          <a href="/.">

            <i class="fa fa-fw fa-dashboard"></i>

            <span class="menu-title">首页</span>
          </a>
        </li>



        <li class="menu-item menu-item-archives">
          <a href="/archives">

            <i class="fa fa-fw fa-delicious"></i>

            <span class="menu-title">归档</span>
          </a>
        </li>



        <li class="menu-item menu-item-categories">
          <a href="/categories">

            <i class="fa fa-fw fa-folder"></i>

            <span class="menu-title">分类</span>
          </a>
        </li>



        <li class="menu-item menu-item-tags">
          <a href="/tags">

            <i class="fa fa-fw fa-tags"></i>

            <span class="menu-title">标签</span>
          </a>
        </li>



        <li class="menu-item menu-item-about">
          <a href="/about">

            <i class="fa fa-fw fa-coffee"></i>

            <span class="menu-title">关于</span>
          </a>
        </li>

      </ul>
      <div class="footer">


    <ul class="social-links">

        <li><a href="https://git.oschina.net/sangshi" target="_blank" title="Github" data-toggle=tooltip data-placement=top><i class="fa fa-github"></i></a></li>

        <li><a href="https://git.oschina.net/sangshi" target="_blank" title="Weibo" data-toggle=tooltip data-placement=top><i class="fa fa-weibo"></i></a></li>

        <li><a href="https://git.oschina.net/sangshi" target="_blank" title="Twitter" data-toggle=tooltip data-placement=top><i class="fa fa-twitter"></i></a></li>

        <li><a href="https://git.oschina.net/sangshi" target="_blank" title="Behance" data-toggle=tooltip data-placement=top><i class="fa fa-behance"></i></a></li>

        <li><a href="/atom.xml" target="_blank" title="Rss" data-toggle=tooltip data-placement=top><i class="fa fa-rss"></i></a></li>

    </ul>

    <div class="copyright">
        &copy; 2017 John Doe<a href="https://beian.miit.gov.cn/" target="_blank">粤ICP备18158798号</a><a href="https://beian.miit.gov.cn/" target="_blank">粤ICP备18158798号</a>
        <div class="publishby">
        	<!-- Powered by <a href="http://hexo.io/" target="_blank">Hexo</a>. -->
        	Theme by <a href="https://github.com/cofess" target="_blank"> cofess </a>base on <a href="https://github.com/cofess/hexo-theme-pure" target="_blank">pure</a>.
        </div>
    </div>
</div>
    </nav>
  </div>
</section>


    <section class="sidebar">
  <div class="slimContent">

      <div class="widget">
    <h3 class="widget-title">公告</h3>
    <div class="widget-body">
        <div id="board">

            <p>您好，您是第<span id="busuanzi_value_site_uv">0</span>位访客</p>

            <div class="content">
                <p>欢迎交流与分享经验!</p>
            </div>
        </div>
    </div>
</div>



  <div class="widget">
    <h3 class="widget-title">分类</h3>
    <div class="widget-body">
      <ul class="category-list"><li class="category-list-item"><a class="category-list-link" href="/categories/NOSQL/">NOSQL</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/git/">git</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/hexo/">hexo</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/其他/">其他</a><span class="category-list-count">1</span></li><li class="category-list-item"><a class="category-list-link" href="/categories/开源项目/">开源项目</a><span class="category-list-count">2</span></li></ul>
    </div>
  </div>




  <div class="widget">
    <h3 class="widget-title">标签</h3>
    <div class="widget-body">
      <ul class="tag-list"><li class="tag-list-item"><a class="tag-list-link" href="/tags/git/">git</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/hexo/">hexo</a><span class="tag-list-count">2</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/hexo-plugins/">hexo plugins</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/nosql/">nosql</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/oschina/">oschina</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/redis/">redis</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/servlet/">servlet</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/商品详情页/">商品详情页</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/电商/">电商</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/码云/">码云</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/tags/配置/">配置</a><span class="tag-list-count">2</span></li></ul>
    </div>
  </div>




  <div class="widget">
    <h3 class="widget-title">标签云</h3>
    <div class="widget-body tagcloud">
      <a href="/tags/git/" style="font-size: 13px;">git</a> <a href="/tags/hexo/" style="font-size: 14px;">hexo</a> <a href="/tags/hexo-plugins/" style="font-size: 13px;">hexo plugins</a> <a href="/tags/nosql/" style="font-size: 13px;">nosql</a> <a href="/tags/oschina/" style="font-size: 13px;">oschina</a> <a href="/tags/redis/" style="font-size: 13px;">redis</a> <a href="/tags/servlet/" style="font-size: 13px;">servlet</a> <a href="/tags/商品详情页/" style="font-size: 13px;">商品详情页</a> <a href="/tags/电商/" style="font-size: 13px;">电商</a> <a href="/tags/码云/" style="font-size: 13px;">码云</a> <a href="/tags/配置/" style="font-size: 14px;">配置</a>
    </div>
  </div>



  <div class="widget">
    <h3 class="widget-title">归档</h3>
    <div class="widget-body">
      <ul class="archive-list"><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/11/">十一月 2017</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/09/">九月 2017</a><span class="archive-list-count">1</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2017/08/">八月 2017</a><span class="archive-list-count">4</span></li><li class="archive-list-item"><a class="archive-list-link" href="/archives/2016/02/">二月 2016</a><span class="archive-list-count">1</span></li></ul>
    </div>
  </div>




  <div class="widget">
    <h3 class="widget-title">最新文章</h3>
    <div class="widget-body">
      <ul class="recent-post-list list-unstyled no-thumbnail">

          <li>

            <div class="item-inner">
              <p class="item-category">
                <a class="category-link" href="/categories/NOSQL/">NOSQL</a>
              </p>
              <p class="item-title">
                <a href="/2017/11/26/Linux-Redis安装配置和使用/" class="title">Linux Redis安装配置和使用</a>
              </p>
              <p class="item-date">
                <time datetime="2017-11-26T05:10:29.000Z" itemprop="datePublished">2017-11-26</time>
              </p>
            </div>
          </li>

          <li>

            <div class="item-inner">
              <p class="item-category">

              </p>
              <p class="item-title">
                <a href="/2017/09/02/商品详情页系统的Servlet3异步化实践-摘抄/" class="title">商品详情页系统的Servlet3异步化实践[摘抄]</a>
              </p>
              <p class="item-date">
                <time datetime="2017-09-02T15:58:37.000Z" itemprop="datePublished">2017-09-02</time>
              </p>
            </div>
          </li>

          <li>

            <div class="item-inner">
              <p class="item-category">
                <a class="category-link" href="/categories/开源项目/">开源项目</a>
              </p>
              <p class="item-title">
                <a href="/2017/08/28/swagger-文档框架/" class="title">swagger 文档框架</a>
              </p>
              <p class="item-date">
                <time datetime="2017-08-28T03:17:25.000Z" itemprop="datePublished">2017-08-28</time>
              </p>
            </div>
          </li>

          <li>

            <div class="item-inner">
              <p class="item-category">
                <a class="category-link" href="/categories/开源项目/">开源项目</a>
              </p>
              <p class="item-title">
                <a href="/2017/08/24/apolo-ctrip-configuration-management-platform-initial-experience/" class="title">Apollo携程配置管理平台初体验</a>
              </p>
              <p class="item-date">
                <time datetime="2017-08-24T14:12:29.000Z" itemprop="datePublished">2017-08-24</time>
              </p>
            </div>
          </li>

          <li>

            <div class="item-inner">
              <p class="item-category">
                <a class="category-link" href="/categories/hexo/">hexo</a>
              </p>
              <p class="item-title">
                <a href="/2017/08/23/hexo-various-configuration-problems/" class="title">Hexo各类配置问题</a>
              </p>
              <p class="item-date">
                <time datetime="2017-08-23T15:56:49.000Z" itemprop="datePublished">2017-08-23</time>
              </p>
            </div>
          </li>

      </ul>
    </div>
  </div>



  </div>
</section>



<section class="main">
  <div class="content">
  <article id="post-商品详情页系统的Servlet3异步化实践-摘抄" class="article article-type-post" itemscope itemprop="blogPost">

    <header class="article-header">



    <h1 class="article-title" itemprop="name">
      商品详情页系统的Servlet3异步化实践[摘抄]
    </h1>



      <div class="article-meta">
        <span class="article-date">
    <i class="fa fa-calendar-check-o"></i>
	<a href="/2017/09/02/商品详情页系统的Servlet3异步化实践-摘抄/" class="article-date">
	  <time datetime="2017-09-02T15:58:37.000Z" itemprop="datePublished">2017-09-02</time>
	</a>
</span>


  <span class="article-tag">
    <i class="fa fa-tag"></i>
	<a class="article-tag-link" href="/tags/servlet/">servlet</a>, <a class="article-tag-link" href="/tags/商品详情页/">商品详情页</a>, <a class="article-tag-link" href="/tags/电商/">电商</a>
  </span>



	<span class="article-read hidden-xs">
	    <i class="fa fa-eye" aria-hidden="true"></i>
	    <span id="busuanzi_container_page_pv">
			阅读<span id="busuanzi_value_page_pv">0</span>次
		</span>
	</span>


        <span class="post-comment"><i class="fa fa-commenting-o"></i> <a href="/2017/09/02/商品详情页系统的Servlet3异步化实践-摘抄/#comments" class="article-comment-link">评论</a></span>


		<span class="post-wordcount hidden-xs">字数统计: 2,481(字)</span>


		<span class="post-readcount hidden-xs">阅读时长: 11(分)</span>


      </div>

    </header>
    <div class="article-entry markdown-body" itemprop="articleBody">

        <p>链接：<a href="http://jinnianshilongnian.iteye.com/blog/2245925" target="_blank" rel="external">原文</a>  作者：张开涛</p>
<blockquote>
<p>在京东工作的这一年多时间里，我在整个商品详情页系统（后端数据源）及商品详情页统一服务系统（页面中异步加载的很多服务，如库存服务、图书相关服务、延保服务等）中使用了Servlet3请求异步化模型，总结了Servlet3请求异步化的一些经验和想法跟大家分享和交流。</p>
</blockquote>
<h3 id="我将从如下几点阐述Servlet3异步化之后的好处："><a href="#我将从如下几点阐述Servlet3异步化之后的好处：" class="headerlink" title="我将从如下几点阐述Servlet3异步化之后的好处："></a>我将从如下几点阐述Servlet3异步化之后的好处：</h3><p>1、为什么实现请求异步化需要使用Servlet3</p>
<p>2、请求异步化后得到的好处是什么</p>
<p>3、如何使用Servlet3异步化</p>
<p>4、一些Servlet3异步化压测数据</p>
<blockquote>
<p>首先说下一般http请求处理的流程：</p>
</blockquote>
<p>1、容器负责接收并解析请求为HttpServletRequest；</p>
<p>2、然后交给Servlet进行业务处理；</p>
<p>3、最后通过HttpServletResponse写出响应。</p>
<p><strong>在Servlet2.x规范中，所有这些处理都是同步进行的，也就是说必须在一个线程中完成从接收请求、业务处理到响应。</strong></p>
<h3 id="1、为什么实现请求异步化需要使用Servlet3"><a href="#1、为什么实现请求异步化需要使用Servlet3" class="headerlink" title="1、为什么实现请求异步化需要使用Servlet3"></a>1、为什么实现请求异步化需要使用Servlet3</h3><blockquote>
<p>此处已Tomcat6举例子，Tomcat6没有实现Servlet3规范，它在处理请求时是通过如下方式实现的：<br>org.apache.catalina.connector.CoyoteAdapter#service</p>
</blockquote>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div></pre></td><td class="code"><pre><div class="line">// Recycle the wrapper request and response</div><div class="line">  if (!comet) &#123;</div><div class="line">      request.recycle();</div><div class="line">      response.recycle();</div><div class="line">  &#125; else &#123;</div><div class="line">      // Clear converters so that the minimum amount of memory</div><div class="line">      // is used by this processor</div><div class="line">      request.clearEncoders();</div><div class="line">      response.clearEncoders();</div><div class="line">  &#125;</div></pre></td></tr></table></figure>
<blockquote>
<p>在请求结束时会同步进行请求的回收，也就是说请求解析、业务处理和响应必须在一个线程内完成，不能跨越线程界限。这也就说明了必须使用实现了Servlet规范的容器进行处理，如Tomcat 7.x。</p>
</blockquote>
<h3 id="2、请求异步化后得到的好处是什么"><a href="#2、请求异步化后得到的好处是什么" class="headerlink" title="2、请求异步化后得到的好处是什么"></a>2、请求异步化后得到的好处是什么</h3><p>2.1、更高的并发能力；<br>2.2、请求解析和业务处理线程池分离；<br>2.3、根据业务重要性对业务分级，并分级线程池；<br>2.4、对业务线程池进行监控、运维、降级等处理。</p>
<h4 id="2-1、更高的并发能力"><a href="#2-1、更高的并发能力" class="headerlink" title="2.1、更高的并发能力"></a>2.1、更高的并发能力</h4><blockquote>
<p>得益于技术的升级，在JDK7配合Tomcat7压测中获得了不错的性能表现。</p>
</blockquote>
<h4 id="2-2、请求解析和业务处理线程池分离"><a href="#2-2、请求解析和业务处理线程池分离" class="headerlink" title="2.2、请求解析和业务处理线程池分离"></a>2.2、请求解析和业务处理线程池分离</h4><blockquote>
<p>在引入Servlet3之前我们的线程模型是如下样子的：</p>
</blockquote>
<p><img src="http://ov81buv8l.bkt.clouddn.com/08f25902-862c-3a65-b874-3f51581082ee.png" alt=""></p>
<blockquote>
<p>整个请求解析、业务处理、生成响应都是由Tomcat线程池进行处理，而且都是在一个线程中处理；不能分离线程处理；比如接收到请求后交给其他线程处理，这样不能灵活定义业务处理模型。</p>
<p>引入Servlet3之后，我们的线程模型可以改造为如下样子：</p>
</blockquote>
<p><img src="http://ov81buv8l.bkt.clouddn.com/bbd7dca3-ae05-3723-b5de-59d2d21153fa.png" alt=""></p>
<blockquote>
<p>此处可以看到请求解析使用Tomcat单线程；而解析完成后会扔到业务队列中，由业务线程池进行处理；这种处理方式可以得到如下好处：</p>
</blockquote>
<p><strong>1、根据业务重要性对业务进行分级，然后根据分级定义线程池；</strong><br><strong>2、可以拿到业务线程池，可以进行很多的操作，比如监控、降级等。</strong></p>
<h4 id="2-3、根据业务重要性对业务分级，并分级线程池"><a href="#2-3、根据业务重要性对业务分级，并分级线程池" class="headerlink" title="2.3、根据业务重要性对业务分级，并分级线程池"></a>2.3、根据业务重要性对业务分级，并分级线程池</h4><blockquote>
<p>在一个系统的发展期间，我们一般把很多服务放到一个系统中进行处理，比如库存服务、图书相关服务、延保服务等等；这些服务中我们可以根据其重要性对业务分级别和做一些限制：</p>
</blockquote>
<p><strong>1、可以把业务分为核心业务级别和非核心业务级别；</strong><br><strong>2、为不同级别的业务定义不同的线程池，线程池之间是隔离的；</strong><br><strong>3、根据业务量定义各级别线程池大小。</strong></p>
<p><img src="http://ov81buv8l.bkt.clouddn.com/780114c2-5669-3295-81df-1e298699e59e.png" alt=""></p>
<p>此时假设非核心业务因为数据库连接池或者网络问题抖动造成响应时间慢，不会对我们核心业务产生影响。</p>
<h4 id="2-4、对业务线程池进行监控、运维、降级等处理"><a href="#2-4、对业务线程池进行监控、运维、降级等处理" class="headerlink" title="2.4、对业务线程池进行监控、运维、降级等处理"></a>2.4、对业务线程池进行监控、运维、降级等处理</h4><blockquote>
<p>因为业务线程池从Tomcat中分离出来，可以进行线程池的监控，比如查看当前处理的请求有多少，是否到了负载瓶颈，到了瓶颈后可以进行业务报警等处理。</p>
</blockquote>
<p><img src="http://ov81buv8l.bkt.clouddn.com/77d5e01c-9613-3aae-93fa-b96b3f2bc8a7.png" alt=""></p>
<blockquote>
<p>上图是我们一个简陋的监控图，可实时查看到当前处理情况：正在处理的任务有多少，队列中等待的任务有多少；可以根据这些数据进行监控和预警。<br>另外我们还可以进行一些简单的运维：</p>
</blockquote>
<p><img src="http://ov81buv8l.bkt.clouddn.com/cd442555-c883-3466-bbfd-71c9ac1afb8b.png" alt=""></p>
<p>对业务线程池进行扩容，或者业务出问题时立即清空线程池防止容器崩溃等问题；而不需要等待容器重启（容器重启需要耗费数十秒甚至数几十毫秒、而且启动后会有预热问题，而造成业务产生抖动）。</p>
<p>如果发现请求处理不过来，负载比较高，最简单的办法就是直接清空线程池，将老请求拒绝掉，而没有雪崩效应。</p>
<p>因为业务队列和业务线程池都是自己的，可以对这些基础组件做很多处理，比如定制业务队列，按照用户级别对用户请求排序，高级别用户得到更高优先级的业务处理。</p>
<h4 id="3、如何使用Servlet3异步化"><a href="#3、如何使用Servlet3异步化" class="headerlink" title="3、如何使用Servlet3异步化"></a>3、如何使用Servlet3异步化</h4><blockquote>
<p>对于Servlet3的使用，可以参考我之前的博客：</p>
</blockquote>
<ul>
<li><a href="http://jinnianshilongnian.iteye.com/blog/1912455" target="_blank" rel="external">Servlet3.1规范（最终版）中文版下载</a></li>
<li><a href="http://jinnianshilongnian.iteye.com/blog/1933108" target="_blank" rel="external">Servlet3.1学习示例</a></li>
</ul>
<blockquote>
<p>而在我项目里使用就比较简单：</p>
</blockquote>
<p>1、接收请求<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div></pre></td><td class="code"><pre><div class="line">@RequestMapping(&quot;/book&quot;)</div><div class="line">public void getBook(HttpServletRequest request, @RequestParam(value=&quot;skuId&quot;) final Long skuId,</div><div class="line">                    @RequestParam(value=&quot;cat1&quot;) final Integer cat1, @RequestParam(value=&quot;cat2&quot;) final Integer cat2) throws Exception &#123;</div><div class="line"></div><div class="line">    oneLevelAsyncContext.submitFuture(request, () -&gt; bookService.getBook(skuId, cat1, cat2));</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>通过一级业务线程池接收请求，并提交业务处理到该线程池；</p>
<p>2、业务线程池封装</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div></pre></td><td class="code"><pre><div class="line">public void submitFuture(final HttpServletRequest req, final Callable&lt;Object&gt; task) &#123;</div><div class="line">    final String uri = req.getRequestURI();</div><div class="line">    final Map&lt;String, String[]&gt; params = req.getParameterMap();</div><div class="line">    final AsyncContext asyncContext = req.startAsync();  //开启异步上下文</div><div class="line">    asyncContext.getRequest().setAttribute(&quot;uri&quot;, uri);</div><div class="line">    asyncContext.getRequest().setAttribute(&quot;params&quot;, params);</div><div class="line">    asyncContext.setTimeout(asyncTimeoutInSeconds * 1000);</div><div class="line">    if(asyncListener != null) &#123;</div><div class="line">        asyncContext.addListener(asyncListener);</div><div class="line">    &#125;</div><div class="line">    executor.submit(new CanceledCallable(asyncContext) &#123; //提交任务给业务线程池</div><div class="line">        @Override</div><div class="line">        public Object call() throws Exception &#123;</div><div class="line">            Object o = task.call();  //业务处理调用</div><div class="line">            if(o == null) &#123;</div><div class="line">                callBack(asyncContext, o, uri, params);  //业务完成后，响应处理</div><div class="line">            &#125;</div><div class="line">            if(o instanceof CompletableFuture) &#123;</div><div class="line">                CompletableFuture&lt;Object&gt; future = (CompletableFuture&lt;Object&gt;)o;</div><div class="line">                future.thenAccept(resultObject -&gt; callBack(asyncContext, resultObject, uri, params))</div><div class="line">                .exceptionally(e -&gt; &#123;</div><div class="line">                    callBack(asyncContext, &quot;&quot;, uri, params);</div><div class="line">                    return null;</div><div class="line">                &#125;);</div><div class="line">            &#125; else if(o instanceof String) &#123;</div><div class="line">                callBack(asyncContext, o, uri, params);</div><div class="line">            &#125;</div><div class="line">            return null;</div><div class="line">        &#125;</div><div class="line">    &#125;);</div><div class="line">&#125;</div><div class="line"></div><div class="line">    private void callBack(AsyncContext asyncContext, Object result, String uri, Map&lt;String, String[]&gt; params) &#123;</div><div class="line">        HttpServletResponse resp = (HttpServletResponse) asyncContext.getResponse();</div><div class="line">        try &#123;</div><div class="line">            if(result instanceof String) &#123;</div><div class="line">                write(resp, (String)result);</div><div class="line">            &#125; else &#123;</div><div class="line">                write(resp, JSONUtils.toJSON(result));</div><div class="line">            &#125;</div><div class="line">        &#125; catch (Throwable e) &#123;</div><div class="line">            resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); //程序内部错误</div><div class="line">            try &#123;</div><div class="line">                LOG.error(&quot;get info error, uri : &#123;&#125;,  params : &#123;&#125;&quot;, uri, JSONUtils.toJSON(params), e);</div><div class="line">            &#125; catch (Exception ex) &#123;</div><div class="line">            &#125;</div><div class="line">        &#125; finally &#123;</div><div class="line">            asyncContext.complete();</div><div class="line">        &#125;</div><div class="line">    &#125;</div></pre></td></tr></table></figure>
<blockquote>
<p>线程池的初始化</p>
</blockquote>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div><div class="line">52</div><div class="line">53</div><div class="line">54</div><div class="line">55</div><div class="line">56</div><div class="line">57</div><div class="line">58</div><div class="line">59</div><div class="line">60</div><div class="line">61</div><div class="line">62</div><div class="line">63</div><div class="line">64</div><div class="line">65</div><div class="line">66</div><div class="line">67</div><div class="line">68</div><div class="line">69</div><div class="line">70</div><div class="line">71</div><div class="line">72</div><div class="line">73</div><div class="line">74</div><div class="line">75</div><div class="line">76</div><div class="line">77</div><div class="line">78</div><div class="line">79</div><div class="line">80</div><div class="line">81</div><div class="line">82</div><div class="line">83</div></pre></td><td class="code"><pre><div class="line">@Override</div><div class="line">public void afterPropertiesSet() throws Exception &#123;</div><div class="line">    String[] poolSizes = poolSize.split(&quot;-&quot;);</div><div class="line">    //初始线程池大小</div><div class="line">    int corePoolSize = Integer.valueOf(poolSizes[0]);</div><div class="line">    //最大线程池大小</div><div class="line">    int maximumPoolSize = Integer.valueOf(poolSizes[1]);</div><div class="line">    queue = new LinkedBlockingDeque&lt;Runnable&gt;(queueCapacity);</div><div class="line">    executor = new ThreadPoolExecutor(</div><div class="line">            corePoolSize, maximumPoolSize,</div><div class="line">            keepAliveTimeInSeconds, TimeUnit.SECONDS,</div><div class="line">            queue);</div><div class="line"></div><div class="line">    executor.allowCoreThreadTimeOut(true);</div><div class="line">    executor.setRejectedExecutionHandler(new RejectedExecutionHandler() &#123;</div><div class="line">        @Override</div><div class="line">        public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) &#123;</div><div class="line">            if(r instanceof CanceledCallable) &#123;</div><div class="line">                CanceledCallable cc = ((CanceledCallable) r);</div><div class="line">                AsyncContext asyncContext = cc.asyncContext;</div><div class="line">                if(asyncContext != null) &#123;</div><div class="line">                    try &#123;</div><div class="line">                        String uri = (String) asyncContext.getRequest().getAttribute(&quot;uri&quot;);</div><div class="line">                        Map params = (Map) asyncContext.getRequest().getAttribute(&quot;params&quot;);</div><div class="line">                        LOG.error(&quot;async request rejected, uri : &#123;&#125;, params : &#123;&#125;&quot;, uri, JSONUtils.toJSON(params));</div><div class="line">                    &#125; catch (Exception e) &#123;&#125;</div><div class="line">                    try &#123;</div><div class="line">                        HttpServletResponse resp = (HttpServletResponse) asyncContext.getResponse();</div><div class="line">                        resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);</div><div class="line">                    &#125; finally &#123;</div><div class="line">                        asyncContext.complete();</div><div class="line">                    &#125;</div><div class="line">                &#125;</div><div class="line">            &#125;</div><div class="line">        &#125;</div><div class="line">    &#125;);</div><div class="line"></div><div class="line">    if(asyncListener == null) &#123;</div><div class="line">        asyncListener = new AsyncListener() &#123;</div><div class="line">            @Override</div><div class="line">            public void onComplete(AsyncEvent event) throws IOException &#123;</div><div class="line">            &#125;</div><div class="line"></div><div class="line">            @Override</div><div class="line">            public void onTimeout(AsyncEvent event) throws IOException &#123;</div><div class="line">                AsyncContext asyncContext = event.getAsyncContext();</div><div class="line">                try &#123;</div><div class="line">                    String uri = (String) asyncContext.getRequest().getAttribute(&quot;uri&quot;);</div><div class="line">                    Map params = (Map) asyncContext.getRequest().getAttribute(&quot;params&quot;);</div><div class="line">                    LOG.error(&quot;async request timeout, uri : &#123;&#125;, params : &#123;&#125;&quot;, uri, JSONUtils.toJSON(params));</div><div class="line">                &#125; catch (Exception e) &#123;&#125;</div><div class="line">                try &#123;</div><div class="line">                    HttpServletResponse resp = (HttpServletResponse) asyncContext.getResponse();</div><div class="line">                    resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);</div><div class="line">                &#125; finally &#123;</div><div class="line">                    asyncContext.complete();</div><div class="line">                &#125;</div><div class="line">            &#125;</div><div class="line"></div><div class="line">            @Override</div><div class="line">            public void onError(AsyncEvent event) throws IOException &#123;</div><div class="line">                AsyncContext asyncContext = event.getAsyncContext();</div><div class="line">                try &#123;</div><div class="line">                    String uri = (String) asyncContext.getRequest().getAttribute(&quot;uri&quot;);</div><div class="line">                    Map params = (Map) asyncContext.getRequest().getAttribute(&quot;params&quot;);</div><div class="line">                    LOG.error(&quot;async request error, uri : &#123;&#125;, params : &#123;&#125;&quot;, uri, JSONUtils.toJSON(params));</div><div class="line">                &#125; catch (Exception e) &#123;&#125;</div><div class="line">                try &#123;</div><div class="line">                    HttpServletResponse resp = (HttpServletResponse) asyncContext.getResponse();</div><div class="line">                    resp.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);</div><div class="line">                &#125; finally &#123;</div><div class="line">                    asyncContext.complete();</div><div class="line">                &#125;</div><div class="line">            &#125;</div><div class="line"></div><div class="line">            @Override</div><div class="line">            public void onStartAsync(AsyncEvent event) throws IOException &#123;</div><div class="line"></div><div class="line">            &#125;</div><div class="line">        &#125;;</div><div class="line">    &#125;</div><div class="line"></div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>3、业务处理<br>执行bookService.getBook(skuId, cat1, cat2)进行业务处理。</p>
<p>4、返回响应<br>在之前封装的异步线程池上下文中直接返回。</p>
<p>5、Tomcat server.xml的配置</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">&lt;Connector port=&quot;1601&quot; asyncTimeout=&quot;10000&quot; acceptCount=&quot;10240&quot; maxConnections=&quot;10240&quot; acceptorThreadCount=&quot;1&quot;  minSpareThreads=&quot;1&quot; maxThreads=&quot;1&quot; redirectPort=&quot;8443&quot; processorCache=&quot;1024&quot; URIEncoding=&quot;UTF-8&quot; protocol=&quot;org.apache.coyote.http11.Http11NioProtocol&quot; enableLookups=&quot;false&quot;/&gt;</div></pre></td></tr></table></figure>
<p>我们升级到了jdk1.8.0_51 +tomcat 8.0.26，在使用Http11Nio2Protocol时遇到一些问题，暂时还是使用的Http11Nio1Protocol。此处可以看到Tomcat线程池我们配置了maxThreads=1，即一个线程进行请求解析。</p>
<h4 id="4、一些Servlet3异步化压测数据"><a href="#4、一些Servlet3异步化压测数据" class="headerlink" title="4、一些Servlet3异步化压测数据"></a>4、一些Servlet3异步化压测数据</h4><p>压测机器基本环境：32核CPU、32G内存；jdk1.7.0_71 + tomcat 7.0.57，服务响应时间在20ms+，使用最简单的单个URL压测吞吐量：</p>
<p>1、使用同步方式压测</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line">siege-3.0.7]# ./src/siege -c100 -t60s -b http://***.item.jd.com/981821</div><div class="line">Transactions: 279187 hits</div><div class="line">Availability: 100.00 %</div><div class="line">Elapsed time: 59.33 secs</div><div class="line">Data transferred: 1669.41 MB</div><div class="line">Response time: 0.02 secs</div><div class="line">Transaction rate: 4705.66 trans/sec</div><div class="line">Throughput: 28.14 MB/sec</div><div class="line">Concurrency: 99.91</div><div class="line">Successful transactions: 279187</div><div class="line">Failed transactions: 0</div><div class="line">Longest transaction: 1.04</div><div class="line">Shortest transaction: 0.00</div></pre></td></tr></table></figure>
<p>2.1、 使用Servlet3异步化压测 100并发、60秒：<br><figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line">siege-3.0.7]# ./src/siege -c100 -t60s -b http://***.item.jd.com/981821 .</div><div class="line">Transactions: 337998 hits</div><div class="line">Availability: 100.00 %</div><div class="line">Elapsed time: 59.09 secs</div><div class="line">Data transferred: 2021.07 MB</div><div class="line">Response time: 0.03 secs</div><div class="line">Transaction rate: 5720.05 trans/sec</div><div class="line">Throughput: 34.20 MB/sec</div><div class="line">Concurrency: 149.79</div><div class="line">Successful transactions: 337998</div><div class="line">Failed transactions: 0</div><div class="line">Longest transaction: 1.07</div><div class="line">Shortest transaction: 0.00</div></pre></td></tr></table></figure></p>
<p>使用Servlet3异步化压测 600并发、60秒：</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line">  收藏代码</div><div class="line">siege-3.0.7]# ./src/siege -c600 -t60s -b http://***.item.jd.com/981821</div><div class="line">Transactions: 370985 hits</div><div class="line">Availability: 100.00 %</div><div class="line">Elapsed time: 59.16 secs</div><div class="line">Data transferred: 2218.32 MB</div><div class="line">Response time: 0.10 secs</div><div class="line">Transaction rate: 6270.88 trans/sec</div><div class="line">Throughput: 37.50 MB/sec</div><div class="line">Concurrency: 598.31</div><div class="line">Successful transactions: 370985</div><div class="line">Failed transactions: 0</div><div class="line">Longest transaction: 1.32</div><div class="line">Shortest transaction: 0.00</div></pre></td></tr></table></figure>
<blockquote>
<p>可以看出异步化之后吞吐量提升了，但是响应时间长了，也就是异步化并不会提升响应时间，但是会增加吞吐量和增加我们需要的灵活性。<br>通过异步化我们不会获得更快的响应时间，但是我们获得了整体吞吐量和我们需要的灵活性：请求解析和业务处理线程池分离；根据业务重要性对业务分级，并分级线程池；对业务线程池进行监控、运维、降级等处理。</p>
</blockquote>


    </div>
    <footer class="article-footer">
      <blockquote class="mt-2x">
  <ul class="post-copyright list-unstyled">

    <li class="post-copyright-link hidden-xs">
      <strong>本文链接：</strong>
      <a href="http://sangshi.oschina.io/2017/09/02/商品详情页系统的Servlet3异步化实践-摘抄/" title="商品详情页系统的Servlet3异步化实践[摘抄]" target="_blank" rel="external">http://sangshi.oschina.io/2017/09/02/商品详情页系统的Servlet3异步化实践-摘抄/</a>
    </li>

    <li class="post-copyright-license">
      <strong>版权声明： </strong> 本博客所有文章除特别声明外，均采用 <a href="http://creativecommons.org/licenses/by/4.0/deed.zh" target="_blank" rel="external">CC BY 4.0 CN协议</a> 许可协议。转载请注明出处！
    </li>
  </ul>
</blockquote>


<div class="panel panel-default panel-badger">
  <div class="panel-body">
    <figure class="media">
      <div class="media-left">
        <a href="https://git.oschina.net/sangshi" target="_blank" class="img-burn thumb-sm visible-lg">
          <img src="/images/avatar.jpg" class="img-rounded w-full" alt="">
        </a>
      </div>
      <div class="media-body">
        <h3 class="media-heading"><a href="https://git.oschina.net/sangshi" target="_blank"><span class="text-dark">sangshi</span><small class="ml-1x">我欲成仙，法力无边</small></a></h3>
        <div>~~~~~~~</div>
      </div>
    </figure>
  </div>
</div>


    </footer>
  </article>


  <div id="comments">


    <div id="uyan_frame"></div>


  </div>



</div>

  <nav class="bar bar-footer clearfix" data-stick-bottom>
  <div class="bar-inner">

  <ul class="pager pull-left">

    <li class="prev">
      <a href="/2017/11/26/Linux-Redis安装配置和使用/" title="Linux Redis安装配置和使用"><i class="fa fa-angle-left" aria-hidden="true"></i>&nbsp;&nbsp;上一篇</a>
    </li>


    <li class="next">
      <a href="/2017/08/28/swagger-文档框架/" title="swagger 文档框架">下一篇&nbsp;&nbsp;<i class="fa fa-angle-right" aria-hidden="true"></i></a>
    </li>

  </ul>



  <div class="bar-right">
    <div class="share-component" data-sites="weibo,qq,wechat,facebook,twitter" data-mobile-sites="weibo,qq,qzone"></div>
  </div>

  </div>
</nav>



</section>

  <script src="https://cdn.bootcss.com/jquery/1.12.4/jquery.min.js"></script>
<script>
window.jQuery || document.write('<script src="js/jquery.min.js"><\/script>')
</script>
<script src="/js/plugin.js"></script>
<script src="/js/application.js"></script>




        <script>
(function (window) {
    var INSIGHT_CONFIG = {
        TRANSLATION: {
            POSTS: '文章',
            PAGES: '页面',
            CATEGORIES: '分类',
            TAGS: '标签',
            UNTITLED: '(未命名)',
        },
        ROOT_URL: '/',
        CONTENT_URL: '/content.json',
    };
    window.INSIGHT_CONFIG = INSIGHT_CONFIG;
})(window);
</script>
<script src="/js/insight.js"></script>



<script defer src="//dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"></script>







    <script defer type="text/javascript" src="http://v2.uyan.cc/code/uyan.js?uid=[object Object]"></script>







</body>
</html>
